package blackberry.util.image;

import net.rim.device.api.system.ApplicationManager;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.Display;
import net.rim.device.api.ui.Field;

public class DjImageResizer{

	private DjImageResizer() {
	}
	
	/**
	 * Bitmap 클래스의 Fit, Fill, Stretch 기능을 활용한다.
	 */
	public static Bitmap fillIntoDisplay(Bitmap oldBitmap, int imageWidth, int imageHeight, 
			int oldBackgroundWidth, int oldBackgroundHeight, long direction, int filterType){
		
		return ImageSizeConverterEngine.convert(
				oldBitmap, 
				imageWidth, 
				imageHeight, 
				oldBackgroundWidth, 
				oldBackgroundHeight, 
				Display.getWidth(), 
				Display.getHeight(), 
				Bitmap.SCALE_TO_FILL,
				direction,
				filterType);
	}
	public static Bitmap fillIntoNewBackground(Bitmap oldBitmap, int imageWidth, int imageHeight, 
			int oldBackgroundWidth, int oldBackgroundHeight, 
			int newBackgroundWidth, int newBackgroundHeight, long direction, int filterType){ 
		
		return ImageSizeConverterEngine.convert(
				oldBitmap, 
				imageWidth, 
				imageHeight, 
				oldBackgroundWidth, 
				oldBackgroundHeight, 
				newBackgroundWidth, 
				newBackgroundHeight, 
				Bitmap.SCALE_TO_FILL,
				direction,
				filterType);
	}
	
	
	/**
	 * fit에서 이미지의 방향을 조절할려면 Image의 Height나 Width중 하나를 더 크게해서 
	 * 여유공간을 마련한다.(Height, Width 모두를 크게하면 이미지자체가 커짐)
	 */
	public static Bitmap fitIntoDisplay(Bitmap oldBitmap, int imageWidth, int imageHeight, 
			int oldBackgroundWidth, int oldBackgroundHeight, long direction, int filterType) {
	
		return ImageSizeConverterEngine.convert(
				oldBitmap, 
				imageWidth, 
				imageHeight, 
				oldBackgroundWidth, 
				oldBackgroundHeight, 
				Display.getWidth(), 
				Display.getHeight(), 
				Bitmap.SCALE_TO_FIT,
				direction,
				filterType);
	}
	public static Bitmap fitIntoNewBackground(Bitmap oldBitmap, int imageWidth, int imageHeight, 
			int oldBackgroundWidth, int oldBackgroundHeight, 
			int newBackgroundWidth, int newBackgroundHeight, long direction, int filterType){ 
		
		return ImageSizeConverterEngine.convert(
				oldBitmap, 
				imageWidth, 
				imageHeight, 
				oldBackgroundWidth, 
				oldBackgroundHeight, 
				newBackgroundWidth, 
				newBackgroundHeight, 
				Bitmap.SCALE_TO_FIT,
				direction,
				filterType);
	}
	
	
	public static Bitmap stretchIntoDisplay(Bitmap oldBitmap, int imageWidth, int imageHeight, 
			int oldBackgroundWidth, int oldBackgroundHeight, int filterType) {
		
		return ImageSizeConverterEngine.convert(
				oldBitmap, 
				imageWidth, 
				imageHeight, 
				oldBackgroundWidth, 
				oldBackgroundHeight, 
				Display.getWidth(), 
				Display.getHeight(), 
				Bitmap.SCALE_STRETCH,
				0,
				filterType);
	}
	public static Bitmap stretchIntoNewBackground(Bitmap oldBitmap, int imageWidth, int imageHeight, 
			int oldBackgroundWidth, int oldBackgroundHeight, 
			int newBackgroundWidth, int newBackgroundHeight, int filterType) {
	
		return ImageSizeConverterEngine.convert(
				oldBitmap, 
				imageWidth, 
				imageHeight, 
				oldBackgroundWidth, 
				oldBackgroundHeight, 
				newBackgroundWidth, 
				newBackgroundHeight, 
				Bitmap.SCALE_STRETCH,
				0,
				filterType);
	}
	
	
	public static Bitmap createTransparentBitmap(int newWidth, int newHeight) {
		
		Bitmap bitmap = new Bitmap(newWidth, newHeight);
	
		bitmap.setARGB(
				getVoidArgb(newWidth, newHeight),
				0, 
				newWidth,
				0, 
				0, 
				newWidth, 
				newHeight);
		
		return bitmap;
	}
	private static int[] getVoidArgb(int newWidth, int newHeight) {
		int[] voidArgb = new int[newWidth * newHeight];
		int argbLeng = voidArgb.length;
		for (int i = 0; i < argbLeng; i++){
			voidArgb[i] = 0;
		}
		return voidArgb;
	}
}


class ImageSizeConverterEngine {

	private ImageSizeConverterEngine() {
	}
	
	public static Bitmap convert(Bitmap oldBitmap, int imageWidth, int imageHeight,
			int oldBackgroundWidth, int oldBackgroundHeight, 
			int newBackgroundWidth, int newBackgroundHeight, 
			int aspectRatio, long direction, int filterType) {

		//NewBackground의 사이즈를 교정한다.
		int[] refinedNewBackgroundSize = new int[2];
		
		if (aspectRatio == Bitmap.SCALE_TO_FIT) {
		
			//Fit의 경우에 Image의 최종 사이즈를 계산하기 전에 
			//OldBackground사이즈를 NewBackground사이즈에 Fit처리를 함으로 인해서 
			//남게되는 부분들을 잘라내서 RefinedNewBackground로 준비해둔다.
			refinedNewBackgroundSize = DjImageCalculator.fitIntoNewBackground(
					oldBackgroundWidth, oldBackgroundHeight, newBackgroundWidth, newBackgroundHeight);
			
		} else {
			
			//FILL, STRETCH는 어차피 입력한 newBackground가 최종 사이즈가 되기 때문에
			//변화를 줄 필요 없다.
			refinedNewBackgroundSize[0] = newBackgroundWidth;
			refinedNewBackgroundSize[1] = newBackgroundHeight;
		}
		
		//최종적으로 반환하게될 Bitmap을 준비한다
		Bitmap newBitmap = null;
		int widthOfNewBitmap = DjImageCalculator.imageWidthIntoNewBackground(
				imageWidth, oldBackgroundWidth, refinedNewBackgroundSize[0]);
		int heightOfNewBitmap = DjImageCalculator.imageHeightIntoNewBackground(
				imageHeight, oldBackgroundHeight, refinedNewBackgroundSize[1]);
		
		
		if (oldBitmap.hasAlpha()) {
			
			newBitmap = DjImageResizer.createTransparentBitmap(
					widthOfNewBitmap , heightOfNewBitmap);
		
		} else {
			
			newBitmap = new Bitmap(widthOfNewBitmap, heightOfNewBitmap);
		}

		
		//STRETCH 일경우에는 간단하게 Return
		if (aspectRatio == Bitmap.SCALE_STRETCH) {
			
			oldBitmap.scaleInto(newBitmap, filterType);
			
			return newBitmap;
	
		
		//FILL, FIT 일 경우에는 Image를 Move하는 과정이 필요하다
		} else {
		
			
			int[] changedSize = applyAspectRatio(oldBitmap, newBitmap, aspectRatio);
			
			//변환 전후의 이미지 크기가 같다면 리소스낭비를 줄이기위해 바로 다음단계로 진행
			if (sameOldSizeAndChangedSize(oldBitmap, changedSize)) {

				moveImage(
						oldBitmap,
						newBitmap, 
						aspectRatio,
						direction,
						filterType);

			//changeImageSize()를 이용해서 적절한 사이즈의 Bitmap을 생성한뒤 다음단계로 진행
			} else {

				moveImage(
						changeImageSize(oldBitmap, changedSize[0], changedSize[1], filterType),
						newBitmap,
						aspectRatio,
						direction,
						filterType);
			}
		}
		
		return newBitmap;
	}

	private static void moveImage(Bitmap srcBitmap, Bitmap newBitmap, 
			int aspectRatio, long direction, int filterType) {
		
		if (aspectRatio == Bitmap.SCALE_TO_FILL) {

			srcBitmap.scaleInto(
					getSrcLeft(srcBitmap, newBitmap, direction),				
					getSrcTop(srcBitmap, newBitmap, direction),
					newBitmap.getWidth(),
					newBitmap.getHeight(), 

					newBitmap,
					0,
					0,
					newBitmap.getWidth(),
					newBitmap.getHeight(),

					filterType);

		} else if (aspectRatio == Bitmap.SCALE_TO_FIT) {

			srcBitmap.scaleInto(
					0,				
					0, 
					srcBitmap.getWidth(),
					srcBitmap.getHeight(), 

					newBitmap,
					getDstLeft(srcBitmap, newBitmap, direction),
					getDstTop(srcBitmap, newBitmap, direction),
					srcBitmap.getWidth(),
					srcBitmap.getHeight(),

					filterType);
		}
	}
	
	private static int getSrcLeft(Bitmap srcBitmap, Bitmap newBitmap, long direction){
		
		
		if (direction == Field.FIELD_HCENTER) {
			return (srcBitmap.getWidth() - newBitmap.getWidth()) / 2;
			
		} else if (direction == Field.FIELD_LEFT) {
			return srcBitmap.getWidth() - newBitmap.getWidth();
		} 
	
		return 0;
	}
	private static int getSrcTop(Bitmap srcBitmap, Bitmap newBitmap, long direction){
		
		if (direction == Field.FIELD_VCENTER) {
			return (srcBitmap.getHeight() - newBitmap.getHeight()) / 2;
			
		} else if (direction == Field.FIELD_TOP) {
			return srcBitmap.getHeight() - newBitmap.getHeight();
		} 
		
		return 0;
	}
	
	private static int getDstLeft(Bitmap srcBitmap, Bitmap newBitmap, long direction){
		
		if (direction == Field.FIELD_HCENTER) {
			return (newBitmap.getWidth() - srcBitmap.getWidth()) / 2;
			
		} else if (direction == Field.FIELD_RIGHT) {
			return newBitmap.getWidth() - srcBitmap.getWidth();
		}
		
		return 0;
	}
	private static int getDstTop(Bitmap srcBitmap, Bitmap newBitmap, long direction){
		
		if (direction == Field.FIELD_VCENTER) {
			return (newBitmap.getHeight() - srcBitmap.getHeight()) / 2;
			
		} else if (direction == Field.FIELD_BOTTOM) {
			return newBitmap.getHeight() - srcBitmap.getHeight();
		} 
		
		return 0;
	}
	
	private static int[] applyAspectRatio(Bitmap oldBitmap, Bitmap newBitmap, int aspectRatio) {
		
		if (aspectRatio == Bitmap.SCALE_TO_FILL) {
			
			return DjImageCalculator.fillIntoNewBackground(
					oldBitmap.getWidth(), oldBitmap.getHeight(), 
					newBitmap.getWidth(), newBitmap.getHeight());
			
		} else if (aspectRatio == Bitmap.SCALE_TO_FIT) {
			
			return DjImageCalculator.fitIntoNewBackground(
					oldBitmap.getWidth(), oldBitmap.getHeight(), 
					newBitmap.getWidth(), newBitmap.getHeight());
		}
		return null;
	}
	
	private static Bitmap changeImageSize(Bitmap oldBitmap, int newWidth, int newHeight, int filterType){
		
		Bitmap changedSizeBitmap = DjImageResizer.createTransparentBitmap(newWidth, newHeight);
		
		oldBitmap.scaleInto(changedSizeBitmap, filterType);
		
		return changedSizeBitmap;
	}	
	
	private static boolean sameOldSizeAndChangedSize(Bitmap oldBitmap, int[] changedSize) {
		return oldBitmap.getWidth() == changedSize[0] 
				&& oldBitmap.getHeight() == changedSize[1];
	}
}
